#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <stdio.h>

using namespace std;

#include "nodo.h"

/****************************************************************
etiqEpilogo es utilizado por prologo y epilogo para la generación
de la etiqueta de dirección del epílogo.
****************************************************************/
static string etiqEpilogo = "";


/****************************************************************
prologo escribe el prólogo de una función, tomando como parámetro 
la entrada en la tabla de símbolos que pertenece a dicha función.

prologo es llamada por "definicion_de_funcion", y se
le envía como parámetro la entrada generada en "nombre_funcion"
****************************************************************/
void prologo(Entrada e) {
	   cout << "\t.text\n.global " << e.nombre << endl
       << ".type " << e.nombre << ",@function" << endl
       << e.nombre << ":" << endl
       << "\tpushl\t%ebp" << endl
       << "\tmovl\t%esp, %ebp" << endl
       << "\tsubl\t$" << (tabla.getLongitudLocales()) << ",%esp" << endl;

  etiqEpilogo = ".epilogo_" + e.nombre;
}


/****************************************************************
epilogo escribe el epilogo de una función al final de 
"definicion_de_funcion".

Se utiliza la variable global etiqEpilogo para marcar la dirección 
del epílogo en el código ensamblador. Esta etiqueta es usada 
posteriormente por los nodos de salto de retorno de función
(NodoRetorno y NodoRetornoVacio)
****************************************************************/
void epilogo(Entrada e) {
  cout << etiqEpilogo << ":" << endl
       << "\tmovl\t%ebp, %esp" << endl
       << "\tpopl\t%ebp" << endl
       << "\tret" << endl;
}

/****************************************************************
Provee la funcionalidad de la generación de etiquetas secuenciales
****************************************************************/

int Nodo::cont = 0;

string Nodo::etiqueta(void) {
  ostringstream os;

  os << ".Lbl" << cont++;
  return string(os.str());
}


/****************************************************************
Genera o muestra secuencialmente los nodos del arbol de la secuencia
****************************************************************/
void NodoSecuencia::generar(void)
{
  sec->generar();
  secs->generar();
}


/****************************************************************
Genera el nodo if.
Tras generar la condición, su resultado queda
almacenado en en al acumulador. 
Se considera cierta la condición si su resultado es distinto de 
cero. Es decir, que se produce el salto si el resultado es igual
a cero. 
****************************************************************/
void NodoIf::generar(void)
{
  string etq_if = etiqueta();

  cond->generar();
  cout << "\tcmpl\t$0, %eax" << endl
       << "\tje\t" << etq_if << endl;
  cierto->generar();
  cout << etq_if << ":" << endl;		
}


/****************************************************************
Genera el nodo if-else.
Tras generar la condición, su resultado queda
almacenado en en al acumulador. 
Se considera cierta la condición si su resultado es distinto de 
cero. Es decir, que se produce el salto condicional si el resultado es igual
a cero. Se produce el salto incondicional al primer bloque en caso 
contrario.
****************************************************************/
void NodoIfElse::generar(void)
{
  string etq_if = etiqueta();
  string etq_else = etiqueta();

  cond->generar();
  cout << "\tcmpl\t$0, %eax" << endl
       << "\tje\t"  << etq_else << endl
       << "\tjmp\t" << etq_if << endl
       << etq_if << ":" << endl;
  cierto->generar();
  cout << etq_else << ":" << endl;
  falso->generar();
}


/****************************************************************
Genera el nodo de retorno con devolución de valor.

Tras generar la expresión a devolver, su resultado 
qued almacenado en en al acumulador.
 
A continuación se produce un salto incondicional al epílogo de la
función.
****************************************************************/
void NodoRetorno::generar(void)
{
  exp->generar();
  cout << "\tjmp\t" << etiqEpilogo << endl;
}


/****************************************************************
Genera el nodo de retorno sin devolución.
 
Simplemente se produce un salto incondicional al epílogo de la
función.
****************************************************************/
void NodoRetornoVacio::generar(void)
{
  cout << "\tjmp\t" << etiqEpilogo << endl;
}



/***************************************************************
Construye el nodo asignación
****************************************************************/

NodoAsignacion::NodoAsignacion(Nodo *i, Nodo * e) : izq(i), expr(e) {

switch(i->tipoNodo->claveTipo) {
	case ERROR:
	tipoNodo.reset(new TipoError("Error en asignación. Variable incorrectamente declarada."));
	break;
	case ENTERO:
	tipoNodo.reset(new TipoEntero);
	break;
	case CARACTER:
	tipoNodo.reset(new TipoChar);
	break;	
}

if(i->tipoNodo->claveTipo==ERROR)
{
	tipoNodo.reset(new TipoError("Error en asignación. Expresión no válida."));
}

//cout << "Tipo Nodo Izquierda:" << i->tipoNodo->nombre() << endl;
//cout << "Tipo Nodo Expresion:" << e->tipoNodo->nombre() << endl;
//cout << "Tipo Nodo Asignacion:" << tipoNodo->nombre() << endl;


}


/****************************************************************
Genera el nodo asignación
 
Tras generar la parte izquierda, el resultado almacenado en %eax
es la dirección efectiva donde hay que almacenar el resultdo de
la parte derecha.

Empujamos en la pila el valor de la dirección, y generamos 
la parte derecha.

Sacamos de la pila la dirección donde hay que almacenar el valor, 
colocandola en %ebx, y finalmente, movemos el valor resultante
(actualmente en %eax) en la dirección de la parte izquierda.
****************************************************************/
void NodoAsignacion::generar(void)
{
    izq->generar();
    cout << "\tpushl\t%eax" << endl;
    expr->generar();
    cout << "\tpopl\t%ebx" << endl;
    
    if(izq->tipoNodo->claveTipo==CARACTER) {
	// Si la parte izquierda es caracter, 
        // pasamos los 8 bits menos significativos
        // a la dirección	
	cout << "\tmovb\t%al,  0(%ebx)" << endl;
	}
    else {
        if(expr->tipoNodo->claveTipo==CARACTER)
	   {
	    // Si la expresion es un caracter, pasamos los ocho
            // bits menos significativos del registro, rellenados con
            // signo (promovemos caracter a entero)
            cout << "\tmovsbl\t%al, %eax" << endl;
            }
	    // Si es entero, movemos el registro completo 
    	    cout << "\tmovl\t%eax, 0(%ebx)" << endl;
	}
}

/****************************************************************
Constructor del nodo suma
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoSuma::NodoSuma(Nodo* i, Nodo* d): izq(i), der(d)
{

if(i->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El sumando izquierdo tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El sumando derecho tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo!=ENTERO && d->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El sumando derecho ha de ser entero o caracter"));
    return;
}

if(i->tipoNodo->claveTipo!=ENTERO && i->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El sumando izquierdo ha de ser entero o caracter"));	
    return;
}


// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}




/****************************************************************
Genera el nodo suma
 
Tras generar la parte derecha, el resultado está almacenado en %eax.

Empujamos en la pila el valor de resultante.

Generamos la parte izquierda, quedando el valor en %eax.

Recuperamos lo guardado en la pila en %ebx, y realizamos la suma
de %ebx sobre %eax, quedando el resultado en %eax.
****************************************************************/
void NodoSuma::generar(void) {
  der->generar();
  cout << "\tpushl\t%eax\n";
  izq->generar();
  cout << "\tpopl\t%ebx\n";
  cout << "\taddl\t%ebx, %eax" << endl;
}

/****************************************************************
Constructor del nodo resta
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoResta::NodoResta(Nodo* i, Nodo* d): izq(i), der(d)
{

if(i->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando izquierdo tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando derecho tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo!=ENTERO && d->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando derecho ha de ser entero o caracter"));
    return;
}

if(i->tipoNodo->claveTipo!=ENTERO && i->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando izquierdo ha de ser entero o caracter"));	
    return;
}


// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}



/****************************************************************
Genera el nodo resta.

Utiliza el mismo esquema que el nodo suma, pero realizando la resta
en lugar de la suma
****************************************************************/
void NodoResta::generar(void) {
  izq->generar();
  cout << "\tpushl\t%eax\n";
  der->generar();
  cout << "\tmovl\t%eax, %ebx\n";
  cout << "\tpopl\t%eax\n";
  cout << "\tsubl\t%ebx, %eax" << endl;
}

/****************************************************************
Constructor del nodo multiplicacion
Aqui se realiza el chequeo de tipos 
****************************************************************/
NodoMult::NodoMult(Nodo* i, Nodo* d): izq(i), der(d)
{

if(i->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando izquierdo tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando derecho tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo!=ENTERO && d->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando derecho ha de ser entero o caracter"));
    return;
}

if(i->tipoNodo->claveTipo!=ENTERO && i->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando izquierdo ha de ser entero o caracter"));	
    return;
}


// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}



/****************************************************************
Genera el nodo multiplicacion.

Utiliza el mismo esquema que el nodo suma, pero realizando la
multiplicación en lugar de la suma
****************************************************************/
void NodoMult::generar(void) {
  der->generar();
  cout << "\tpushl\t%eax\n";
  izq->generar();
  cout << "\tpopl\t%ebx\n";
  cout << "\timull\t%ebx, %eax" << endl;
}


/****************************************************************
Constructor del nodo division
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoDivision::NodoDivision(Nodo* i, Nodo* d): izq(i), der(d)
{

if(i->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando izquierdo tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando derecho tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo!=ENTERO && d->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando derecho ha de ser entero o caracter"));
    return;
}

if(i->tipoNodo->claveTipo!=ENTERO && i->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando izquierdo ha de ser entero o caracter"));	
    return;
}


// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}

/****************************************************************
Genera el nodo división.

Utiliza el mismo esquema que el nodo suma, pero realizando la
división en lugar de la suma
****************************************************************/
void NodoDivision::generar(void) {
  der->generar();
  cout << "\tpushl\t%eax\n";
  izq->generar();
  cout << "\tpopl\t%ebx\n";
  cout << "\tcdq\n";
  cout << "\tdivl\t%ebx" << endl;
}

/****************************************************************
Constructor del nodo modulo
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoModulo::NodoModulo(Nodo* i, Nodo* d): izq(i), der(d)
{

if(i->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando izquierdo tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando derecho tiene un error de compilación"));
    return;	
}

if(d->tipoNodo->claveTipo!=ENTERO && d->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando derecho ha de ser entero o caracter"));
    return;
}

if(i->tipoNodo->claveTipo!=ENTERO && i->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando izquierdo ha de ser entero o caracter"));	
    return;
}


// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}


/****************************************************************
Genera el nodo modulo.

Utiliza el mismo esquema que el nodo división, pero colocando el 
valor de %edx en el acumulador antes de salir.
****************************************************************/
void NodoModulo::generar(void) {
  der->generar();
  cout << "\tpushl\t%eax\n";
  izq->generar();
  cout << "\tpopl\t%ebx\n";
  cout << "\tcdq\n";
  cout << "\tdivl\t%ebx\n";
  cout << "\tmovl\t%edx, %eax" << endl;
}


NodoLlamada::NodoLlamada(string* nombre, ListaParametros* p): nom(nombre), params(p) {

try
{	
	// Buscamos la referencia en la tabla de simbolos de la funcion
	Entrada ent = tabla.buscar((*nombre));
	if(ent.art != FUNCION) {
		tipoNodo.reset(new TipoError("Se esta intentando llamar a un simbolo que no es una funcion"));
		return;
	}


	switch(ent.val) {

	case ERROR:
	// Pasa el error al siguiente nivel
	tipoNodo.reset(new TipoError("Detectada una llamada incorrecta a una funcion"));
	return;

	case ENTERO:
	tipoNodo.reset(new TipoEntero);
	break;
	case CARACTER:
	tipoNodo.reset(new TipoChar);
	break;
	case VOID:
	tipoNodo.reset(new TipoVoid);
	break;
	default:
	tipoNodo.reset(new TipoError("Tipo no compatible con funcion"));	
        }

	// Chequear el parametro si existe, y si viene con algun valor
	if(ent.numeroDeParametros == 1 && p->size()==1)
	{
		Nodo *nodoPar; 
		nodoPar = (*p)[0];
		
		if(nodoPar->tipoNodo->claveTipo==ERROR)
		{
	          tipoNodo.reset(new TipoError("El parametro de la funcion es erroneo"));
		  return;	
		}

		if( nodoPar->tipoNodo->claveTipo!=ENTERO 
			&& nodoPar->tipoNodo->claveTipo!=CARACTER
			&& nodoPar->tipoNodo->claveTipo!=VOID )
		{
	          tipoNodo.reset(new TipoError("El parametro de una función solo puede ser entero, caracter o void"));
		  return;	
		}


	}
	
	
}
catch(ExElementoNoExiste& ex)
{
	// Como nosotros no implementamos la declaración de funciones,
	// si la función no existe en la tabla de simbolos,
        // asumimos "optmimisticamente" que alguna otra unidad de compliación
        // la va a tener. De esta forma, permitimos la ejecución de los 
	// printf en nuestro compilador.
	// El tipo de nuestra función lo fijamos a void, sin embargo.
	tipoNodo.reset(new TipoVoid);  
}

}


/****************************************************************
Destructor del nodo llamada.

Los punteros de ListaParametros no son manejados por un recolector 
de basura. Por tanto, los objetos de la lista han de ser destruidos
antes de la destrucción de la lista.
****************************************************************/
NodoLlamada::~NodoLlamada() {
  for (ListaParametros::iterator it = params->begin();
       it != params->end(); ++it) 
    {
      delete *it;
    }
}

/****************************************************************
Genera la llamada a una función

Comienza obteniendo los valores a pasar como parámetros en orden 
inverso, y empujandolos en la pila.

Se produce la llamada, y se produce la recuperación de la pila
en una cantidad de memoria igual al tamaño de la pila utilizado
por los parámetros.
****************************************************************/
void NodoLlamada::generar(void) {


  for (ListaParametros::reverse_iterator it = params->rbegin();
       it != params->rend(); ++it) 
    {
      (*it)->generar();
      cout << "\tpushl\t%eax" << endl;
    }

  cout << "\tcall\t" << *nom << endl;
  cout << "\taddl\t$" << (params->size()*4) << ",%esp" << endl;
}



/****************************************************************
Genera el resultado del nodo constante entera, dejando disponible 
en el acumulador el valor expresado por el valor constante almacenado
en el nodo.
****************************************************************/
void NodoConstanteEntera::generar(void) {
  cout << "\tmovl\t$" << num << ", %eax\n";
}


/****************************************************************
Genera el resultado del nodo constante entera, dejando disponible 
en el acumulador el valor expresado por el valor constante almacenado
en el nodo.
****************************************************************/
void NodoConstanteChar::generar(void) {
  
  char buffer [10];
  sprintf(buffer,"%d",caracter);
  //Copia el entero que representa el valor ascii del caracter
  //en ocho bits al registro %al 
  cout << "\tmovb\t$" << buffer << ", %al\n";
}


/****************************************************************
Inicializa a cero el contador de constantes de cadenas
****************************************************************/
int NodoConstanteCadena::cont = 0;


map <string,int> NodoConstanteCadena::tablaCadenas;


/****************************************************************
La generación del NodoConstanteCadena consiste en mover al acumulador la dirección
donde está almacenada la cadena el en segmento .rodata
****************************************************************/
void NodoConstanteCadena::generar(void) {
  cout << "\tmovl\t$.S" << etiqueta << ", %eax\n";
}

NodoIdentificadorLVal::NodoIdentificadorLVal(Entrada pE) : e(pE) {

switch(pE.val)
{
	case ENTERO:
		tipoNodo.reset(new TipoEntero);
		break;
	case CARACTER:
		tipoNodo.reset(new TipoChar);
		break;
	default:
		tipoNodo.reset(new TipoError("Una variable sólo puede ser del tipo char o del tipo int"));	
}


}




/****************************************************************
La generación delNodoIdentificadorLVal consiste en mover al acumulador la dirección
efectiva, en caso de tratarse de almacenamiento dinámico, o directamente
mover la dirección en caso de tratarse de almacenamiento estático.
****************************************************************/
void NodoIdentificadorLVal::generar(void) {
  if (e.alm != ESTATICO) {
    cout << "\tleal\t" << e.direccion << ", %eax" << endl;
  } else {
    cout << "\tmovl\t" << e.direccion << ", %eax" << endl;
  }
}


void NodoVacio::generar(void) {
  // vacio
}


/****************************************************************
Constructor del nodo MenosUnario
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoMenosUnario::NodoMenosUnario(Nodo* nod): n(nod)
{

if(n->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando del menos unario tiene un error de compilacion"));
    return;	
}

if(n->tipoNodo->claveTipo!=ENTERO && n->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando operando del menos unario ha de ser entero o caracter"));
    return;
}

// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}



/****************************************************************
EL nodo menos unario sencillamente multiplica el acumulador por -1
****************************************************************/
void NodoMenosUnario::generar(void) {
  n->generar();  cout << "\tnegl\t%eax" << endl;  
}


/****************************************************************
Constructor del nodo MenosUnario
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoMasUnario::NodoMasUnario(Nodo* nod): n(nod)
{

if(n->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando del mas unario tiene un error de compilacion"));
    return;	
}

if(n->tipoNodo->claveTipo!=ENTERO && n->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando operando del mas unario ha de ser entero o caracter"));
    return;
}

// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}


/****************************************************************
EL nodo mas unario No realiza ninguna operacion, simplemente pasa
el valor al siguiente nivel.
****************************************************************/
void NodoMasUnario::generar(void) {
  n->generar();  
}

/****************************************************************
Constructor del nodo Inremento Prefijo
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoIncPrefijo::NodoIncPrefijo(Nodo* nod): n(nod)
{

if(n->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando del incremento prefijo tiene un error de compilacion"));
    return;	
}

if(n->tipoNodo->claveTipo!=ENTERO && n->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando operando del inc prefijo ha de ser entero o caracter"));
    return;
}

// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}




/****************************************************************
La generación del nodoInc prefijo comienza generando la parte_izquierda,
que deja una dirección efectiva (la de la "variable") en el acumulador.

Guardamos el valor de dicha dirección en la pila.

Movemos el valor de la variable al acumulador, y lo incrementamos
a uno.

Recuperamos la dirección de la parte_izquierda de la pila al registro %ebx,
y movemos el valor de %eax a dicha dirección. 
****************************************************************/
void NodoIncPrefijo::generar(void) {
  
  n->generar();
  cout << "\tpushl\t%eax" << endl;

  if(n->tipoNodo->claveTipo==ENTERO) {
  	cout << "\tmovl\t(%eax), %eax\n";
  }
  else {
	// Si el operando es un caracter, he de mover solo
        // 8 bits al acumulador
	cout << "\tmovsbl\t(%eax), %eax\n";
  }

  cout << "\tincl\t%eax\n";
  cout << "\tpopl\t%ebx" << endl;  cout << "\tmovl\t%eax, 0(%ebx)" << endl;  
}


/****************************************************************
Constructor del nodo decremento prefijo
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoDecPrefijo::NodoDecPrefijo(Nodo* nod): n(nod)
{

if(n->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando del decremento prefijo tiene un error de compilacion"));
    return;	
}

if(n->tipoNodo->claveTipo!=ENTERO && n->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando operando del decremento prefijo ha de ser entero o caracter"));
    return;
}

// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}


/****************************************************************
La generación del NodoDecPrefijo sigue el mismo esquema que NodoIncPrefijo, 
pero decrementando en lugar de incrementando.
****************************************************************/
void NodoDecPrefijo::generar(void) {
  
  n->generar();
  cout << "\tpushl\t%eax" << endl;

  if(n->tipoNodo->claveTipo==ENTERO) {
  	cout << "\tmovl\t(%eax), %eax\n";
  }
  else {
	// Si el operando es un caracter, he de mover solo
        // 8 bits al acumulador
	cout << "\tmovsbl\t(%eax), %eax\n";
  }

  cout << "\tdecl\t%eax\n";
  cout << "\tpopl\t%ebx" << endl;  cout << "\tmovl\t%eax, 0(%ebx)" << endl;  
}


/****************************************************************
Constructor del nodo incremento sufijo
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoIncSufijo::NodoIncSufijo(Nodo* nod): n(nod)
{

if(n->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando del incremento sufijo tiene un error de compilacion"));
    return;	
}

if(n->tipoNodo->claveTipo!=ENTERO && n->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando operando del incremento sufijo ha de ser entero o caracter"));
    return;
}

// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}


/****************************************************************
La generación del NodoIncSufijo sigue el mismo esquema que nodoIncPrefijo, 
pero decrementando el valor en el acumulador al final, de forma que 
queda inmutado el valor que sa pasa al siguiente nivel.
****************************************************************/
void NodoIncSufijo::generar(void) {
  
  n->generar();
  cout << "\tpushl\t%eax" << endl;

  if(n->tipoNodo->claveTipo==ENTERO) {
  	cout << "\tmovl\t(%eax), %eax\n";
  }
  else {
	// Si el operando es un caracter, he de mover solo
        // 8 bits al acumulador
	cout << "\tmovsbl\t(%eax), %eax\n";
  }

  cout << "\tincl\t%eax\n";
  cout << "\tpopl\t%ebx" << endl;  cout << "\tmovl\t%eax, 0(%ebx)" << endl;
  cout << "\tdecl\t%eax\n";  
}


/****************************************************************
Constructor del nodo decremento sufijo
Aqui se realiza el chequeo de tipos
****************************************************************/
NodoDecSufijo::NodoDecSufijo(Nodo* nod): n(nod)
{

if(n->tipoNodo->claveTipo==ERROR)
{
    tipoNodo.reset(new TipoError("El operando del decremento sufijo tiene un error de compilacion"));
    return;	
}

if(n->tipoNodo->claveTipo!=ENTERO && n->tipoNodo->claveTipo!=CARACTER)
{
    tipoNodo.reset(new TipoError("El operando operando del decremento sufijo ha de ser entero o caracter"));
    return;
}

// Esta operacion de vuelve enteros siempre
 tipoNodo.reset(new TipoEntero);

}



/****************************************************************
La generación del NodoDecSufijo sigue el mismo esquema que NodoDecPrefijo, 
pero incrementando el valor en el acumulador al final, de forma que 
queda inmutado el valor que se pasa al siguiente nivel.
****************************************************************/
void NodoDecSufijo::generar(void) {
  
  n->generar();
  cout << "\tpushl\t%eax" << endl;

  if(n->tipoNodo->claveTipo==ENTERO) {
  	cout << "\tmovl\t(%eax), %eax\n";
  }
  else {
	// Si el operando es un caracter, he de mover solo
        // 8 bits al acumulador
	cout << "\tmovsbl\t(%eax), %eax\n";
  }

  cout << "\tdecl\t%eax\n";
  cout << "\tpopl\t%ebx" << endl;  cout << "\tmovl\t%eax, 0(%ebx)" << endl;
  cout << "\tincl\t%eax\n";  
}


/**************************************************************
El nodo LValue toma el tipo de aquello que lo compone. En nuestro
caso un identificador, por lo que nos limitamos a copiar el 
mismo tipo que trae.
***************************************************************/
NodoLValue::NodoLValue(Nodo* nod): n(nod) {

switch(n->tipoNodo->claveTipo) {
	case ERROR:
	// Pasa el error al siguiente nivel
	tipoNodo.reset(new TipoError("La declaración era incorrecta"));
	break;
	case ENTERO:
	tipoNodo.reset(new TipoEntero);
	break;
	case CARACTER:
	tipoNodo.reset(new TipoChar);
	break;
	default:
	tipoNodo.reset(new TipoError("Tipo no compatible con variable"));	
}

};


/****************************************************************
Nodo LValue pasa el contenido que está en la dirección de memoria 
al registro de la arquitectura, para que esté dispuesto para la 
siguiente operación.

****************************************************************/
void NodoLValue::generar() {
  n->generar();
  switch(n->tipoNodo->claveTipo) {
	case ENTERO:
	 // Mueve el contenido de 64 bits al registro
	 cout << "\tmovl\t(%eax), %eax" << endl;
	break;
	case CARACTER:
	// Mueve sólo ocho bits, rellenando con el signo
	 cout << "\tmovsbl\t(%eax), %eax" << endl;
	break; 
  }
};



